package com.ag.improvedjava.iterable;

import java.util.Iterator;
import java.util.NoSuchElementException;

import com.ag.improvedjava.utils.Predicate;

final class WhereIterable<E> implements Iterable<E> {

	private Iterable<E> iterable;
	private Predicate<E> predicate;
	
	WhereIterable(Iterable<E> iterable, Predicate<E> predicate) {
		this.iterable = iterable;
		this.predicate = predicate;
	}

	@Override
	public Iterator<E> iterator() {
		return new WhereIterator<>(iterable.iterator(), predicate);
	}
	
}

class WhereIterator<E> extends UnmodifiableIterator<E> {
	
	private Iterator<E> iterator;
	private Predicate<E> predicate;
	private E cachedElement;
	
	private boolean timeToIterate;
	private boolean endOfIterator;
	
	
	WhereIterator(Iterator<E> iterator, Predicate<E> predicate) {
		this.iterator = iterator;
		this.predicate = predicate;
		this.timeToIterate = true;
	}

	@Override
	public boolean hasNext() {
		if (timeToIterate) {
			moveToNextEligibleElement();
		}
		return !endOfIterator;
	}

	@Override
	public E next() {
		if (!hasNext()) {
			throw new NoSuchElementException();
		}
		timeToIterate = true;
		return cachedElement;
	}

	private void moveToNextEligibleElement() {
		
		timeToIterate = false;
		
		while (iterator.hasNext()) {
			E next = iterator.next();
			if (predicate.evaluate(next)) {
				cachedElement = next;
				return;
			}
		}
		endOfIterator = true;
	}
	
}
